{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "bso-fs_rl.ipynb",
      "version": "0.3.2",
      "provenance": [],
      "collapsed_sections": [],
      "toc_visible": true,
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/Neofly4023/bso-fs/blob/master/bso_fs_rl.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "metadata": {
        "id": "gcOEaw7-Tzcn",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        "# Feature selection using reinforcement learning"
      ]
    },
    {
      "metadata": {
        "id": "LlZENNNdT6A2",
        "colab_type": "code",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "import pandas as pd\n",
        "import numpy as np\n",
        "import os, glob, random, copy, sys, time, re\n",
        "from collections import defaultdict\n",
        "from sklearn import metrics\n",
        "from sklearn.model_selection import train_test_split, cross_val_score, KFold, StratifiedKFold, \\\n",
        "ShuffleSplit\n",
        "from sklearn.neighbors import KNeighborsClassifier\n",
        "from sklearn.svm import SVC\n",
        "from sklearn.preprocessing import StandardScaler\n",
        "from oauth2client.client import GoogleCredentials\n",
        "from google.colab import drive\n",
        "!pip install xlsxwriter\n",
        "import xlsxwriter\n",
        "\n",
        "gdrive_path = '/content/gdrive'\n",
        "drive.mount(gdrive_path)\n",
        "\n",
        "class Bee :\n",
        "    def __init__(self,id,problem,locIterations):\n",
        "        self.id=id\n",
        "        self.data=problem\n",
        "        self.solution=[]\n",
        "        self.fitness= 0.0\n",
        "        self.reward = 0.0\n",
        "        self.locIterations=locIterations\n",
        "        self.action = []\n",
        "    \n",
        "    def localSearch(self):\n",
        "        best=self.fitness\n",
        "        #done=False\n",
        "        lista=[j for j, n in enumerate(self.solution) if n == 1]\n",
        "        indice =lista[0]\n",
        "        \n",
        "        for itr in range(self.locIterations):\n",
        "            while(True):\n",
        "                pos=-1\n",
        "                oldFitness=self.fitness\n",
        "                for i in range(len(self.solution)):\n",
        "                    \n",
        "                    if ((len(lista)==1) and (indice==i) and (i < self.data.nb_attribs-1)):\n",
        "                        i+=1\n",
        "                    self.solution[i]= (self.solution[i] + 1) % 2\n",
        "                    \n",
        "                    quality = self.data.evaluate(self.solution)\n",
        "                    if (quality >best):\n",
        "                        pos = i\n",
        "                        best=quality\n",
        "                    self.solution[i]= (self.solution[i]+1) % 2\n",
        "                    self.fitness = oldFitness \n",
        "                if (pos != -1):\n",
        "                    self.solution[pos]= (self.solution[pos]+1)%2\n",
        "                    self.fitness = best\n",
        "                else:\n",
        "                    break\n",
        "            for i in range(len(self.solution)):\n",
        "                oldFitness=self.fitness\n",
        "                if ((len(lista)==1) and (indice==i) and (i < self.data.nb_attribs-1)):\n",
        "                    i+=1\n",
        "                self.solution[i]= (self.solution[i] + 1) % 2\n",
        "                quality = self.data.evaluate(self.solution)\n",
        "                if (quality<best):\n",
        "                    self.solution[i]= (self.solution[i] + 1) % 2\n",
        "                    self.fitness = oldFitness\n",
        "\n",
        "\n",
        "    def ql_localSearch(self):\n",
        "        \n",
        "        iterations = int(self.locIterations/4) if self.locIterations >= 4 else 1\n",
        "        for itr in range(iterations):\n",
        "       \n",
        "            state = self.solution.copy()\n",
        "\n",
        "            next_state, action = self.data.ql.step(self.data,state)\n",
        "            acc_state = self.data.evaluate(state)\n",
        "            acc_new_state = self.data.evaluate(next_state)\n",
        "\n",
        "            if (acc_state < acc_new_state):\n",
        "                self.reward = acc_new_state\n",
        "            elif (acc_state > acc_new_state):\n",
        "                self.reward = acc_new_state - acc_state\n",
        "            else :\n",
        "                if (self.data.nbrUn(state) > self.data.nbrUn(next_state) ):\n",
        "                    self.reward = 0.5 * acc_new_state\n",
        "                else :\n",
        "                    self.reward = -0.5 * acc_new_state\n",
        "\n",
        "            self.fitness = self.data.ql.get_q_value(self.data,state,action)\n",
        "            self.data.ql.learn(self.data,state,action,self.reward,next_state)\n",
        "            self.solution = next_state.copy()\n",
        "        \n",
        "       \n",
        "    def setSolution(self,solution):\n",
        "        self.solution=solution.copy()\n",
        "        self.fitness=self.data.evaluate(solution)\n",
        "    \n",
        "    def Rand(self,num): \n",
        "        res = [] \n",
        "        res = np.random.choice([0,1],size=(num,),p=[2./10,8./10]).tolist()\n",
        "  \n",
        "        return res\n",
        "\n",
        "\n",
        "\n",
        "class Swarm :\n",
        "    def __init__(self,problem,flip,maxChance,nbrBees,maxIterations,locIterations):\n",
        "        self.data=problem\n",
        "        self.flip=flip\n",
        "        self.maxChance=maxChance\n",
        "        self.nbChance=maxChance\n",
        "        self.nbrBees=nbrBees\n",
        "        self.maxIterations=maxIterations\n",
        "        self.locIterations=locIterations\n",
        "        self.beeList=[]\n",
        "        self.refSolution = Bee(-1,self.data,self.locIterations)\n",
        "        self.refSolution.setSolution(self.refSolution.Rand(self.data.nb_attribs))\n",
        "        self.bestSolution = self.refSolution\n",
        "        self.tabou=[]\n",
        "\n",
        "    def searchArea(self):    \n",
        "        i=0\n",
        "        h=0\n",
        "        \n",
        "        self.beeList=[]\n",
        "        while((i<self.nbrBees) and (i < self.flip) ) :\n",
        "            #print (\"First method to generate\")\n",
        "            \n",
        "            solution=self.refSolution.solution.copy()\n",
        "            k=0\n",
        "            while((self.flip*k+h) < len(solution)):\n",
        "                solution[self.flip*k +h] = ((solution[self.flip*k+h]+1) % 2)\n",
        "                k+=1\n",
        "            newBee=Bee(i,self.data,self.locIterations)\n",
        "            #newBee.solution = copy.deepcopy(solution)\n",
        "            newBee.solution = solution.copy()\n",
        "            self.beeList.append(newBee)\n",
        "            \n",
        "            i+=1\n",
        "            h=h+1\n",
        "        h=0\n",
        "        \n",
        "        while((i<self.nbrBees) and (i< 2*self.flip )):\n",
        "            #print(\"Second method to generate\")\n",
        "\n",
        "            solution=self.refSolution.solution.copy()\n",
        "            k=0\n",
        "            while((k<int(len(solution)/self.flip)) and (self.flip*k+h < len(solution))):\n",
        "                solution[int(self.data.nb_attribs/self.flip)*h+k] = ((solution[int(self.data.nb_attribs/self.flip)*h+k]+1)%2)\n",
        "                k+=1\n",
        "            newBee=Bee(i,self.data,self.locIterations)\n",
        "            #newBee.solution = copy.deepcopy(solution)\n",
        "            newBee.solution = solution.copy()\n",
        "            self.beeList.append(newBee)\n",
        "            \n",
        "            i+=1\n",
        "            h=h+1\n",
        "        while (i<self.nbrBees):\n",
        "            #print(\"Random method to generate\")\n",
        "            solution= self.refSolution.solution.copy()\n",
        "            indice = random.randint(0,len(solution)-1)\n",
        "            solution[indice]=((solution[indice]+1) % 2)\n",
        "            newBee=Bee(i,self.data,self.locIterations)\n",
        "            #newBee.solution = copy.deepcopy(solution)\n",
        "            newBee.solution = solution.copy()\n",
        "            self.beeList.append(newBee)\n",
        "            i+=1\n",
        "        for bee in (self.beeList):\n",
        "            lista=[j for j, n in enumerate(bee.solution) if n == 1]\n",
        "            if (len(lista)== 0):\n",
        "                bee.setSolution(bee.Rand(self.data.nb_attribs))\n",
        "                \n",
        "    def selectRefSol(self,typeOfAlgo):\n",
        "      typeOfAlgo = typeOfAlgo\n",
        "      if (typeOfAlgo == 0):\n",
        "        self.beeList.sort(key=lambda Bee: Bee.fitness, reverse=True)\n",
        "        bestQuality=self.beeList[0].fitness\n",
        "        if(bestQuality>self.bestSolution.fitness):\n",
        "            self.bestSolution=self.beeList[0]\n",
        "            self.nbChance=self.maxChance\n",
        "            return self.bestSolution\n",
        "        else:\n",
        "            if(  (len(self.tabou)!=0) and  bestQuality > (self.tabou[len(self.tabou)-1].fitness)  ):\n",
        "                self.nbChance=self.maxChance\n",
        "                return self.bestBeeQuality(typeOfAlgo)\n",
        "            else:\n",
        "                self.nbChance-=1\n",
        "                if(self.nbChance > 0): \n",
        "                    return self.bestBeeQuality(typeOfAlgo)\n",
        "                else :\n",
        "                    return self.bestBeeDiversity()\n",
        "      \n",
        "      elif (typeOfAlgo == 1):\n",
        "        self.beeList.sort(key=lambda Bee: Bee.reward, reverse=True)\n",
        "        bestQuality=self.beeList[0].reward\n",
        "        if(bestQuality>self.bestSolution.reward):\n",
        "            self.bestSolution=self.beeList[0]\n",
        "            self.nbChance=self.maxChance\n",
        "            return self.bestSolution\n",
        "        else:\n",
        "            if(  (len(self.tabou)!=0) and  bestQuality > (self.tabou[len(self.tabou)-1].reward)  ):\n",
        "                self.nbChance=self.maxChance\n",
        "                return self.bestBeeQuality(typeOfAlgo)\n",
        "            else:\n",
        "                self.nbChance-=1\n",
        "                if(self.nbChance > 0): \n",
        "                    return self.bestBeeQuality(typeOfAlgo)\n",
        "                else :\n",
        "                    return self.bestBeeDiversity()                  \n",
        "\n",
        "    def distanceTabou(self,bee):\n",
        "        distanceMin=self.data.nb_attribs\n",
        "        for i in range(len(self.tabou)):\n",
        "            cpt=0\n",
        "            for j in range(self.data.nb_attribs):\n",
        "                if (bee.solution[j] != self.tabou[i].solution[j]) :\n",
        "                      cpt +=1\n",
        "            if (cpt<=1) :\n",
        "                return 0\n",
        "            if (cpt < distanceMin) :\n",
        "                distanceMin=cpt\n",
        "        return distanceMin\n",
        "    \n",
        "    def bestBeeQuality(self,typeOfAlgo):\n",
        "        distance = 0\n",
        "        i=0\n",
        "        pos=-1\n",
        "        while(i<self.nbrBees):\n",
        "            if (typeOfAlgo == 0):\n",
        "              max_val=self.beeList[i].fitness\n",
        "            if (typeOfAlgo == 1):\n",
        "              max_val=self.beeList[i].reward  \n",
        "\n",
        "            nbUn=self.data.nbrUn(self.beeList[i].solution)\n",
        "            while((i<self.nbrBees) and (self.data.evaluate(self.beeList[i].solution) == max_val)):\n",
        "                distanceTemp=self.distanceTabou(self.beeList[i])\n",
        "                nbUnTemp = self.data.nbrUn(self.beeList[i].solution)\n",
        "                if(distanceTemp > distance) or ((distanceTemp == distance) and (nbUnTemp < nbUn)):\n",
        "                    if((distanceTemp==distance) and (nbUnTemp<nbUn)):\n",
        "                        print(\"We pick the solution with less features\")\n",
        "                    nbUn=nbUnTemp\n",
        "                    distance=distanceTemp\n",
        "                    pos=i\n",
        "                i+=1\n",
        "            if(pos!=-1) :\n",
        "                return self.beeList[pos]\n",
        "        bee= Bee(-1,self.data,self.locIterations)\n",
        "        bee.setSolution(bee.Rand(self.data.nb_attribs))\n",
        "        return bee\n",
        "            \n",
        "    def bestBeeDiversity(self):\n",
        "        max_val=0\n",
        "        for i in range(len(self.beeList)):\n",
        "            if (self.distanceTabou(self.beeList[i])> max_val) :\n",
        "                max_val = self.distanceTabou(self.beeList[i])\n",
        "        if (max_val==0):\n",
        "            bee= Bee(-1,self.data,self.locIterations)\n",
        "            bee.setSolution(bee.Rand(self.data.nb_attribs))\n",
        "            return bee\n",
        "        i=0\n",
        "        while(i<len(self.beeList) and self.distanceTabou(self.beeList[i])!= max_val) :\n",
        "            i+=1\n",
        "        return self.beeList[i]\n",
        "    \n",
        "    def bso(self,typeOfAlgo):\n",
        "        i=0\n",
        "        while(i<self.maxIterations):\n",
        "            #print(\"refSolution is : \",self.refSolution.solution)\n",
        "            self.tabou.append(self.refSolution)\n",
        "            #print(\"Iteration N° : \",i)\n",
        "            \n",
        "            self.searchArea()\n",
        "\n",
        "            #La recherche locale\n",
        "            \n",
        "            for j in range(self.nbrBees):\n",
        "              if (typeOfAlgo == 0):\n",
        "                self.beeList[j].localSearch()\n",
        "              elif (typeOfAlgo == 1):\n",
        "                for episode in range(self.locIterations):\n",
        "                  self.beeList[j].ql_localSearch()\n",
        "                #print( \"Q-value of bee \" + str(j) + \" solution is : \" + str(self.beeList[j].fitness))\n",
        "            self.refSolution = self.selectRefSol(typeOfAlgo)\n",
        "            i+=1\n",
        "        print(\"[BSO parameters used]\\n\")\n",
        "        print(\"Type of algo : {0}\".format(typeOfAlgo))\n",
        "        print(\"Flip : {0}\".format(self.flip))\n",
        "        print(\"MaxChance : {0}\".format(self.maxChance))\n",
        "        print(\"Nbr of Bees : {0}\".format(self.nbrBees))\n",
        "        print(\"Nbr of Max Iterations : {0}\".format(self.maxIterations))\n",
        "        print(\"Nbr of Loc Iterations : {0}\\n\".format(self.locIterations))\n",
        "        print(\"Best solution found : \",self.bestSolution.solution)\n",
        "        print(\"Number of features used : {0}\".format(self.data.nbrUn(self.bestSolution.solution)))\n",
        "        print(\"Accuracy : {0:.2f} \".format(self.bestSolution.fitness*100))\n",
        "        #print(\"Return (Q-value) : \",self.bestSolution.fitness)\n",
        "        return self.bestSolution.fitness*100, self.data.nbrUn(self.bestSolution.solution)\n",
        "\n",
        "    \n",
        "    def str_sol(self,mlist):\n",
        "        result = ''\n",
        "        for element in mlist:\n",
        "            result += str(element)\n",
        "        return result\n",
        "\n",
        "      \n",
        "class QLearning:\n",
        "    def __init__(self,nb_atts,actions):\n",
        "        self.actions = actions\n",
        "        self.alpha = 0.1 # Facteur d'apprentissage\n",
        "        self.gamma = 0.9\n",
        "        self.epsilon = 0.1\n",
        "        self.q_table = [ {} for i in range(nb_atts) ] #defaultdict(lambda : [0.0,0.0,0.0,0.0])\n",
        "\n",
        "    def get_max_value(self,data,state,actions_vals):\n",
        "        max_val = 0.0\n",
        "        arg_max = 0\n",
        "        for i in actions_vals:\n",
        "            if self.get_q_value(data,state,i) >= max_val:\n",
        "                max_val = self.get_q_value(data,state,i)\n",
        "                arg_max = i\n",
        "        if max_val == 0:\n",
        "            arg_max = np.random.choice(actions_vals)\n",
        "        return max_val,arg_max\n",
        "\n",
        "\n",
        "    def get_q_value(self,data,state,action):\n",
        "        if not self.str_sol(state) in self.q_table[self.nbrUn(state)]:\n",
        "            self.q_table[self.nbrUn(state)][self.str_sol(state)] = {}\n",
        "\n",
        "        if not str(action) in self.q_table[self.nbrUn(state)][self.str_sol(state)]:\n",
        "            self.q_table[self.nbrUn(state)][self.str_sol(state)][str(action)] = data.evaluate(self.get_next_state(state,action))\n",
        "            self.q_table[self.nbrUn(state)][self.str_sol(state)][str(action)] = 0\n",
        "            \n",
        "        return self.q_table[self.nbrUn(state)][self.str_sol(state)][str(action)]\n",
        "\n",
        "    def set_q_value(self,state,action,val):\n",
        "        self.q_table[self.nbrUn(state)][self.str_sol(state)][str(action)] = val\n",
        "\n",
        "    def step(self,data,state):\n",
        "        if np.random.uniform() > self.epsilon :\n",
        "            action_values = self.actions\n",
        "            argmax_actions=[] \n",
        "            for ac in action_values :\n",
        "\n",
        "                ac_state_q_val = self.get_q_value(data,state,ac)\n",
        "                if ( ac_state_q_val >= self.get_max_value(data,state,action_values)[0] ):\n",
        "                    #print(\"Q-value for action :\" + str(ac) + \" is \" + str(ac_state_q_val))\n",
        "                    argmax_actions.append(ac)\n",
        "\n",
        "            #print(\"This is argmax list : \",argmax_actions)\n",
        "            if len(argmax_actions) != 0:\n",
        "              next_action = np.random.choice(argmax_actions) \n",
        "            else:\n",
        "              next_action = np.random.choice(action_values) \n",
        "            next_state = self.get_next_state(state,next_action)\n",
        "            #print(\"The next state is :\",next_state)\n",
        "            \n",
        "            #reward = data.evaluate(next_state)\n",
        "        else :\n",
        "            next_action = np.random.choice(self.actions)\n",
        "            next_state = self.get_next_state(state,next_action)\n",
        "            \n",
        "            #reward = reward = data.evaluate(next_state)\n",
        "            \n",
        "        if self.epsilon > 0 :\n",
        "            self.epsilon -= 0.0001 \n",
        "        if self.epsilon < 0 :\n",
        "            self.epsilon = 0\n",
        "\n",
        "        return next_state, next_action #, reward\n",
        "\n",
        "\n",
        "    def get_next_state(self,state,action):\n",
        "        next_state = state.copy()\n",
        "        next_state[action] = (next_state[action]+1) % 2\n",
        "        if (self.nbrUn(next_state) != 0):\n",
        "          return next_state\n",
        "        else:\n",
        "          return state\n",
        "    \n",
        "    def learn(self,data,current_state,current_action,reward,next_state):\n",
        "        #print(\"current state : \" + self.str_sol(current_state) + \"| current action : \" + str(current_action) + \"| reward : \"+ str(reward) + \"| next state : \"+ self.str_sol(next_state))\n",
        "        \n",
        "        next_action = self.step(data,next_state)[1] # step returns 3 values : next_state, next_action, and the reward\n",
        "        new_q = reward + self.gamma * self.get_q_value(data,next_state,next_action)  #[0] is to pick q-value instead of [1] which is the accuracy of the new state \n",
        "        self.set_q_value(current_state,current_action,(1 - self.alpha)*self.get_q_value(data,current_state,current_action) + self.alpha*new_q)  \n",
        "\n",
        "    #@staticmethod\n",
        "    def str_sol(self,mlist):\n",
        "        result = ''\n",
        "        for element in mlist:\n",
        "            result += str(element)\n",
        "        return result\n",
        "\n",
        "    def nbrUn(self,solution):\n",
        "        return len([i for i, n in enumerate(solution) if n == 1])\n",
        "\n",
        "      \n",
        "      \n",
        "class FsProblem :\n",
        "    def __init__(self,data,qlearn):\n",
        "        self.data=data\n",
        "        self.nb_attribs= len(self.data.columns)-1 \n",
        "        self.outPuts=self.data.iloc[:,self.nb_attribs]\n",
        "        self.ql = qlearn\n",
        "        self.nb_actions = len(self.ql.actions)\n",
        "        self.classifier = KNeighborsClassifier(n_neighbors=1)\n",
        "\n",
        "    def evaluate2(self,solution):\n",
        "        list=[i for i, n in enumerate(solution) if n == 1]\n",
        "        if (len(list) == 0):\n",
        "            return 0\n",
        "         \n",
        "        df = self.data.iloc[:,list]\n",
        "        array=df.values\n",
        "        nb_attribs =len(array[0])\n",
        "        X = array[:,0:nb_attribs]\n",
        "        Y = self.outPuts\n",
        "        train_X, test_X, train_y, test_y = train_test_split(X, Y, \n",
        "                                                    random_state=0,\n",
        "                                                    test_size=0.1\n",
        "                                                    )\n",
        "        classifier = KNeighborsClassifier(n_neighbors=1)\n",
        "        classifier.fit(train_X,train_y)\n",
        "        predict= classifier.predict(test_X) \n",
        "        return metrics.accuracy_score(predict,test_y)\n",
        "    \n",
        "    def evaluate(self,solution):\n",
        "        list=[i for i, n in enumerate(solution) if n == 1]\n",
        "        if (len(list)== 0):\n",
        "            return 0\n",
        "        df = self.data.iloc[:,list]        \n",
        "        array=df.values\n",
        "        nbrAttributs =len(array[0])\n",
        "        X = array[:,0:nbrAttributs]\n",
        "        Y = self.outPuts\n",
        "        cv = ShuffleSplit(n_splits=10, test_size=0.1, random_state=0)\n",
        "        results = cross_val_score(self.classifier, X, Y, cv=cv,scoring='accuracy')\n",
        "        #print(\"\\n[Cross validation results]\\n{0}\".format(results))\n",
        "        return results.mean()\n",
        "    \n",
        "    def nbrUn(self,solution):\n",
        "        return len([i for i, n in enumerate(solution) if n == 1])\n",
        "\n",
        "class FSData:\n",
        "\n",
        "    def __init__(self,location,nbr_exec):\n",
        "        \n",
        "        self.location = location\n",
        "        self.nb_exec = nbr_exec\n",
        "        self.dataset_name = re.search('[A-Za-z\\-]*.csv',self.location)[0].split('.')[0]\n",
        "        self.df = pd.read_csv(self.location,header=None)\n",
        "        self.ql = QLearning(len(self.df.columns),self.attributs_to_flip(len(self.df.columns)-1))\n",
        "        self.fsd = FsProblem(self.df,self.ql)\n",
        "        \n",
        "        self.classifier_name = str(type(self.fsd.classifier)).strip('< > \\' class ').split('.')[3]\n",
        "        path = gdrive_path + '/My Drive/Colab Notebooks/results/'+ self.dataset_name\n",
        "        self.instance_name = str(time.strftime(\"%d-%m-%Y_%H-%M_\", time.localtime()) + self.dataset_name + '_' + self.classifier_name)\n",
        "        log_filename = str(path + '/logs/'+ self.instance_name)\n",
        "        \n",
        "        log_file = open(log_filename + '.txt','w+')\n",
        "        sys.stdout = log_file\n",
        "        \n",
        "        print(\"[START] Dataset\" + self.dataset_name + \"description \\n\")\n",
        "        print(\"Shape : \" + str(self.df.shape) + \"\\n\")\n",
        "        print(self.df.describe())\n",
        "        print(\"\\n[END] Dataset\" + self.dataset_name + \"description\\n\")\n",
        "        print(\"[START] Ressources specifications\\n\")\n",
        "        !cat /proc/cpuinfo\n",
        "        print(\"[END] Ressources specifications\\n\")\n",
        "\n",
        "        \n",
        "        sheet_filename = str(path + '/sheets/'+ self.instance_name )\n",
        "        self.workbook = xlsxwriter.Workbook(sheet_filename + '.xlsx')\n",
        "        \n",
        "        self.worksheet = self.workbook.add_worksheet(self.classifier_name)\n",
        "        self.worksheet.write(0,0,'Iteration')\n",
        "        self.worksheet.write(0,1,'Accuracy')\n",
        "        self.worksheet.write(0,2,'N_Features')\n",
        "        self.worksheet.write(0,3,'Time')\n",
        "    \n",
        "    def attributs_to_flip(self,nb_att):\n",
        "      \n",
        "        return list(range(nb_att))\n",
        "    \n",
        "    def run(self,typeOfAlgo,flip,maxChance,nbrBees,maxIterations,locIterations):\n",
        "        t_init = time.time()\n",
        "        \n",
        "        for itr in range(1,self.nb_exec+1):\n",
        "          print (\"Execution N°{0}\".format(str(itr)))\n",
        "          self.ql = QLearning(len(self.df.columns),self.attributs_to_flip(len(self.df.columns)-1))\n",
        "          self.fsd = FsProblem(self.df,self.ql)\n",
        "          swarm = Swarm(self.fsd,flip,maxChance,nbrBees,maxIterations,locIterations)\n",
        "          t1 = time.time()\n",
        "          best = swarm.bso(typeOfAlgo)\n",
        "          t2 = time.time()\n",
        "          print(\"Time elapsed for execution N°{0} : {1:.2f} s\\n\".format(itr,t2-t1))\n",
        "          self.worksheet.write(itr, 0, itr)\n",
        "          self.worksheet.write(itr, 1, \"{0:.2f}\".format(best[0]))\n",
        "          self.worksheet.write(itr, 2, best[1])\n",
        "          self.worksheet.write(itr, 3, \"{0:.3f}\".format(t2-t1))\n",
        "          \n",
        "        t_end = time.time()\n",
        "        print (\"Total execution time for dataset {0} is {1:.2f} s\".format(self.dataset_name,t_end-t_init))\n",
        "        self.workbook.close()\n",
        "\n",
        "        \n",
        "# Main program\n",
        "\n",
        "# Prepare the dataset\n",
        "\n",
        "dataset = \"Glass\"\n",
        "data_loc_path = \"https://raw.githubusercontent.com/Neofly4023/bso-fs/master/datasets/\"\n",
        "location = data_loc_path + dataset + \".csv\"\n",
        "\n",
        "# Params init\n",
        "\n",
        "typeOfAlgo = 0\n",
        "nbr_exec = 1\n",
        "flip = 5\n",
        "maxChance = 3\n",
        "nbrBees = 10\n",
        "maxIterations = 2\n",
        "locIterations = 2\n",
        "\n",
        "instance = FSData(location,nbr_exec)\n",
        "instance.run(typeOfAlgo,flip,maxChance,nbrBees,maxIterations,locIterations)\n"
      ],
      "execution_count": 0,
      "outputs": []
    }
  ]
}